﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using CodeStash.Common.DataAccess.EntityFramework;
using CodeStash.Common.DataAccess.Repository;
using CodeStash.Common.DataAccess.UnitOfWork;
using CodeStash.Common.Encryption;
using CodeStash.Filters;
using CodeStash.Models.Security;
using CodeStash.Services;
using CodeStash.Services.Contracts;




namespace CodeStash.Controllers
{
    public class TeamController : BaseTagCloudEnabledController
    {

        private readonly IMembershipService membershipService;
        private readonly IMembershipDataProvider membershipDataProvider;
        private readonly ILoggerService loggerService;
        private readonly IRepository<OwnedTeam> ownedTeamRepository;
        private readonly IRepository<CreatedTeam> createdTeamRepository;
        private readonly IUnitOfWork unitOfWork;



        public TeamController(IMembershipService membershipService,
            IMembershipDataProvider membershipDataProvider,
            ILoggerService loggerService, 
            ITagCloudService tagCloudService,
            IRepository<OwnedTeam> ownedTeamRepository, 
            IRepository<CreatedTeam> createdTeamRepository,
            IUnitOfWork unitOfWork)
            : base(tagCloudService)
        {
            this.membershipService = membershipService;
            this.membershipDataProvider = membershipDataProvider;
            this.loggerService = loggerService;
            this.ownedTeamRepository = ownedTeamRepository;
            this.createdTeamRepository = createdTeamRepository;
            this.unitOfWork = unitOfWork;
        }



        [Authorize]
        [RenderTagCloud]
        [HttpGet]
        public ActionResult Index()
        {
            loggerService.Info("Team : Showing team page");
            return View();
        }


        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult SaveNewTeam(string teamName)
        {
            if (!string.IsNullOrEmpty(teamName))
            {
                using (unitOfWork)
                {
                    ownedTeamRepository.EnrolInUnitOfWork(unitOfWork);
                    createdTeamRepository.EnrolInUnitOfWork(unitOfWork);


                    MembershipUser user = membershipService.GetUserByUserName(User.Identity.Name);
                    if (!ownedTeamRepository.FindBy(x => x.TeamDescription.ToLower() == teamName.ToLower()).Any())
                    {
                        OwnedTeam ownedTeam = new OwnedTeam(Guid.Parse(user.ProviderUserKey.ToString()), teamName);
                        ownedTeamRepository.Add(ownedTeam);
                        unitOfWork.Commit();
                        loggerService.Info("Team : Creating owned team");

                        createdTeamRepository.Add(new CreatedTeam(ownedTeam.TeamId, Guid.Parse(user.ProviderUserKey.ToString())));
                        unitOfWork.Commit();

                        loggerService.Info("Team : Creating team sucessfully");
                        return Json(new { Message = "Team Added Successfully", Success = true });
                    }
                    else
                    {
                        loggerService.Error("Team : Couldn't create new team as TeamName already exists");
                        return Json(new { Message = "Team Already Exists", Success = false });
                    }

                }
            }
            else
            {
                loggerService.Error("Team : Couldn't create new team as TeamName was empty");
                return Json(new { Message = "You did not enter a valid TeamName", Success = false });
            }

        }


        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult GetOwnedTeams()
        {
            using (unitOfWork)
            {
                ownedTeamRepository.EnrolInUnitOfWork(unitOfWork);
                MembershipUser user = membershipService.GetUserByUserName(User.Identity.Name);
                List<OwnedTeam> teams= ownedTeamRepository.FindBy(x => x.TeamOwnerAspMembershipUserId == Guid.Parse(user.ProviderUserKey.ToString())).ToList();
                loggerService.Info(string.Format("Team : GetOwnedTeams() called which found {0}, teams for user '{1}'", teams.Count(), user.UserName));
                
                return Json(new { Message = teams, Success = true });
                
            }
        }



        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult GetTeamMembersForSpecificTeam(int teamId)
        {
            try
            {
                using (unitOfWork)
                {
                    createdTeamRepository.EnrolInUnitOfWork(unitOfWork);
                    List<CreatedTeam> createdTeams = createdTeamRepository.FindBy(x => x.TeamId == teamId).ToList();
                    List<DirectLookupUserModel> usersInTeam = new List<DirectLookupUserModel>();
                    foreach (CreatedTeam createdTeam in createdTeams)
                    {
                        DirectLookupUserModel userModel = membershipDataProvider.GetUserDataForUserId(createdTeam.AspMembershipUserId);
                        loggerService.Info(string.Format("Team : Fetcing {0} who is part of CreatedTeam '{1}'", userModel.UserName, createdTeam.CreatedTeamId));
                        usersInTeam.Add(userModel);
                    }
                    return Json(new { Message = usersInTeam, Success = true });
                }
            }
            catch
            {
                loggerService.Error(string.Format("Team : There was a problem fetching team members for selected team '{0}'", teamId));
                return Json(new { Message = "There was a problem fetching team members for selected team", Success = false });
            }
        }



        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult AssignMemberToTeam(int teamId, string teamMemberId)
        {
            try
            {
                using (unitOfWork)
                {
                    createdTeamRepository.EnrolInUnitOfWork(unitOfWork);
                    Guid userId = Guid.Parse(teamMemberId);

                    if (createdTeamRepository.FindBy(x => x.TeamId == teamId && x.AspMembershipUserId == userId).Any())
                    {
                        loggerService.Error(string.Format("Team : The selected user '{0}', is already a member of the chosen team '{1}'", teamMemberId, teamId));
                        return Json(new { Message = "The selected user is already a member of the chosen team", Success = false });
                    }
                    
                    createdTeamRepository.Add(new CreatedTeam(teamId, userId));
                    unitOfWork.Commit();
                    loggerService.Info(string.Format("Team : Sucessfully added user '{0}', to team '{1}'", teamMemberId, teamId));
                    return Json(new { Message = "Sucessfully added team member", Success = true });
                }
            }
            catch
            {
                loggerService.Error(string.Format("Team : Failed to assign team member '{0}' to team '{1}'", teamMemberId, teamId));
                return Json(new { Message = "Failed to assign selected member to team", Success = false });
            }
        }



        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult DeleteMemberFromTeam(int teamId, string teamMemberId)
        {
            try
            {
                using (unitOfWork)
                {
                    createdTeamRepository.EnrolInUnitOfWork(unitOfWork);
                    Guid userId = Guid.Parse(teamMemberId);
                    CreatedTeam team = createdTeamRepository.FindBy(x => x.TeamId == teamId && x.AspMembershipUserId == userId).FirstOrDefault();
                    createdTeamRepository.Remove(team);
                    unitOfWork.Commit();
                    loggerService.Info(string.Format("Team : Sucessfully removed team member '{0}' from team '{1}'", teamMemberId, teamId));
                    return Json(new { Message = "Sucessfully removed team member", Success = true });
                }
            }
            catch
            {
                loggerService.Error(string.Format("Team : Failed to remove team member '{0}' from team '{1}'", teamMemberId, teamId));
                return Json(new { Message = "Failed to remove team member", Success = false });
            }
        }



        [Authorize]
        [HttpPost]
        [AjaxOnly]
        public ActionResult SearchForUsers(string email, bool isOpenIdlogin)
        {
            
            if(!string.IsNullOrEmpty(email))
            {

                loggerService.Info(string.Format("Team : Searching for users with email address '{0}' where IsOpenIdLogin = '{1}'", email, isOpenIdlogin));
         
                List<DirectLookupUserModel> userModels1 = membershipDataProvider.GetUserDataForEmailAddress(email);
                List<DirectLookupUserModel> userModels = userModels1.Where(x => x.IsOpenIdLoggedInUser == isOpenIdlogin).ToList();

                string encryptedEmail = EncryptionHelper.GetEncryptedValue(email);
                List<DirectLookupUserModel> userModels2 = membershipDataProvider.GetUserDataForEmailAddress(encryptedEmail);
                userModels.AddRange(userModels2.Where(x => x.IsOpenIdLoggedInUser == isOpenIdlogin).ToList());

                if (userModels.Any())
                {
                    loggerService.Info(string.Format("Team : Found {0} matching user with email address '{1}' where IsOpenIdLogin = '{2}'", userModels.Count(), email, isOpenIdlogin));
                    return Json(new { Message = userModels, Success = true });
                }
                else
                {
                    loggerService.Error(string.Format("Team : Could not find any matching user with email address '{0}'", email));
                    return Json(new { Message = "Could not find any matching users with the email adress specified", Success = false });
                }
            }
            else
            {
                loggerService.Error("Team : Could not search for user, you need to supply an email");
                return Json(new { Message = "You need to specify a email", Success = false });
            }

        }
    }
}
